import tkinter as tk
from tkinter import filedialog, messagebox, ttk
import threading
import os
import pygame
import time
from tts_handler import TTSHanlder
from config import SILICONFLOW_API_KEY, DEFAULT_MODEL, DEFAULT_VOICE, DEFAULT_RESPONSE_FORMAT


class TTSApplication:
    def __init__(self, root):
        self.root = root
        self.root.title("文本朗读工具")
        self.root.geometry("600x500")
        
        # 初始化TTS处理器
        self.tts = TTSHanlder()
        
        # 检查API密钥
        if SILICONFLOW_API_KEY == "your_api_key_here":
            messagebox.showwarning("警告", "请先设置硅基流动API密钥环境变量: SILICONFLOW_API_KEY")
        
        # 创建界面
        self.create_widgets()
        
        # 播放控制变量
        self.is_playing = False
        self.current_segment = 0
        self.audio_segments = []  # (index, audio_data, file_path)
        self.segment_paths = []
        self.segments = []  # 原始文本段落
        self.output_dir = ""
        
    def create_widgets(self):
        # 文件选择区域
        file_frame = ttk.Frame(self.root, padding="10")
        file_frame.pack(fill=tk.X)
        
        ttk.Label(file_frame, text="选择文本文件:").pack(side=tk.LEFT)
        self.file_path_var = tk.StringVar()
        ttk.Entry(file_frame, textvariable=self.file_path_var, width=50).pack(side=tk.LEFT, padx=(5, 5))
        ttk.Button(file_frame, text="浏览", command=self.browse_file).pack(side=tk.LEFT)
        
        # 参数设置区域
        params_frame = ttk.LabelFrame(self.root, text="参数设置", padding="10")
        params_frame.pack(fill=tk.X, padx=10, pady=5)
        
        # 模型设置
        model_frame = ttk.Frame(params_frame)
        model_frame.pack(fill=tk.X, pady=2)
        ttk.Label(model_frame, text="模型:").pack(side=tk.LEFT)
        self.model_var = tk.StringVar(value=DEFAULT_MODEL)
        ttk.Entry(model_frame, textvariable=self.model_var, width=30).pack(side=tk.LEFT, padx=(5, 0))
        
        # 语音设置
        voice_frame = ttk.Frame(params_frame)
        voice_frame.pack(fill=tk.X, pady=2)
        ttk.Label(voice_frame, text="语音:").pack(side=tk.LEFT)
        self.voice_var = tk.StringVar(value=DEFAULT_VOICE)
        ttk.Entry(voice_frame, textvariable=self.voice_var, width=30).pack(side=tk.LEFT, padx=(5, 0))
        
        # 音频格式设置
        format_frame = ttk.Frame(params_frame)
        format_frame.pack(fill=tk.X, pady=2)
        ttk.Label(format_frame, text="格式:").pack(side=tk.LEFT)
        self.format_var = tk.StringVar(value=DEFAULT_RESPONSE_FORMAT)
        ttk.Combobox(format_frame, textvariable=self.format_var, 
                    values=["mp3", "wav", "pcm", "opus"], width=10).pack(side=tk.LEFT, padx=(5, 0))
        
        # 段落大小设置
        segment_frame = ttk.Frame(params_frame)
        segment_frame.pack(fill=tk.X, pady=2)
        ttk.Label(segment_frame, text="段落大小:").pack(side=tk.LEFT)
        self.segment_size_var = tk.StringVar(value="1000")
        ttk.Entry(segment_frame, textvariable=self.segment_size_var, width=10).pack(side=tk.LEFT, padx=(5, 0))
        ttk.Label(segment_frame, text="字符").pack(side=tk.LEFT, padx=(2, 0))
        
        # 段落范围选择区域
        range_frame = ttk.LabelFrame(self.root, text="段落范围选择", padding="10")
        range_frame.pack(fill=tk.X, padx=10, pady=5)
        
        ttk.Label(range_frame, text="从第").pack(side=tk.LEFT)
        self.start_segment_var = tk.StringVar(value="1")
        ttk.Spinbox(range_frame, from_=1, to=1000, textvariable=self.start_segment_var, width=5).pack(side=tk.LEFT, padx=(2, 2))
        ttk.Label(range_frame, text="段到第").pack(side=tk.LEFT)
        self.end_segment_var = tk.StringVar(value="1")
        ttk.Spinbox(range_frame, from_=1, to=1000, textvariable=self.end_segment_var, width=5).pack(side=tk.LEFT, padx=(2, 2))
        ttk.Label(range_frame, text="段").pack(side=tk.LEFT)
        
        # 控制按钮区域
        control_frame = ttk.Frame(self.root, padding="10")
        control_frame.pack(fill=tk.X)
        
        self.load_btn = ttk.Button(control_frame, text="加载文件", command=self.load_file)
        self.load_btn.pack(side=tk.LEFT, padx=(0, 5))
        
        self.convert_btn = ttk.Button(control_frame, text="转换选中段落", command=self.convert_selected, state=tk.DISABLED)
        self.convert_btn.pack(side=tk.LEFT, padx=(0, 5))
        
        self.play_btn = ttk.Button(control_frame, text="播放", command=self.toggle_play, state=tk.DISABLED)
        self.play_btn.pack(side=tk.LEFT, padx=(0, 5))
        
        self.stop_btn = ttk.Button(control_frame, text="停止", command=self.stop_playback, state=tk.DISABLED)
        self.stop_btn.pack(side=tk.LEFT, padx=(0, 5))
        
        # 进度条区域
        progress_frame = ttk.LabelFrame(self.root, text="播放进度", padding="10")
        progress_frame.pack(fill=tk.X, padx=10, pady=5)
        
        self.progress_var = tk.DoubleVar()
        self.progress_bar = ttk.Progressbar(progress_frame, variable=self.progress_var, maximum=100)
        self.progress_bar.pack(fill=tk.X, pady=(0, 5))
        
        self.progress_label = ttk.Label(progress_frame, text="请选择文件并点击加载")
        self.progress_label.pack()
        
        # 段落进度
        segment_frame = ttk.Frame(progress_frame)
        segment_frame.pack(fill=tk.X, pady=(5, 0))
        self.segment_label = ttk.Label(segment_frame, text="段落: 0/0")
        self.segment_label.pack()
        
    def browse_file(self):
        file_path = filedialog.askopenfilename(
            title="选择文本文件",
            filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")]
        )
        if file_path:
            self.file_path_var.set(file_path)
            
    def load_file(self):
        file_path = self.file_path_var.get()
        if not file_path:
            messagebox.showerror("错误", "请选择要转换的文本文件")
            return
            
        if not os.path.exists(file_path):
            messagebox.showerror("错误", "文件不存在")
            return
            
        try:
            # 读取文件内容
            self.progress_label.config(text="正在读取文件...")
            text = self.tts.read_text_file(file_path)
            if not text:
                messagebox.showerror("错误", "无法读取文件内容")
                return
                
            if not text.strip():
                messagebox.showerror("错误", "文件内容为空")
                return
                
            # 获取段落大小参数
            try:
                segment_size = int(self.segment_size_var.get())
            except ValueError:
                messagebox.showerror("错误", "段落大小必须是数字")
                return
                
            # 设置段落大小
            self.tts.max_chars_per_segment = segment_size
            
            # 分割文本
            self.progress_label.config(text="正在分割文本...")
            self.segments = self.tts.split_text_into_segments(text)
            
            # 创建保存音频文件的目录
            base_name = os.path.splitext(os.path.basename(file_path))[0]
            self.output_dir = f"{base_name}_audio"
            if not os.path.exists(self.output_dir):
                os.makedirs(self.output_dir)
                
            # 更新段落范围选择
            self.start_segment_var.set("1")
            self.end_segment_var.set(str(len(self.segments)))
            
            # 配置Spinbox的最大值
            for child in self.root.winfo_children():
                if isinstance(child, ttk.LabelFrame):
                    for subchild in child.winfo_children():
                        if isinstance(subchild, ttk.Spinbox):
                            subchild.config(to=len(self.segments))
                            
            # 更新UI
            self.convert_btn.config(state=tk.NORMAL)
            self.progress_label.config(text=f"文件加载完成，共 {len(self.segments)} 段")
            self.segment_label.config(text=f"段落: 0/{len(self.segments)}")
            
            # 清除之前的音频数据
            self.audio_segments = []
            self.segment_paths = []
            self.current_segment = 0
            
        except Exception as e:
            messagebox.showerror("错误", f"加载文件过程中出现错误: {str(e)}")
            
    def convert_selected(self):
        if not self.segments:
            messagebox.showerror("错误", "请先加载文件")
            return
            
        # 获取段落范围
        try:
            start_segment = int(self.start_segment_var.get()) - 1  # 转换为0基索引
            end_segment = int(self.end_segment_var.get()) - 1
            
            # 验证范围
            if start_segment < 0 or end_segment >= len(self.segments) or start_segment > end_segment:
                messagebox.showerror("错误", "段落范围无效")
                return
                
        except ValueError:
            messagebox.showerror("错误", "段落范围必须是数字")
            return
            
        # 获取参数
        model = self.model_var.get()
        voice = self.voice_var.get()
        response_format = self.format_var.get()
        
        # 在后台线程中进行转换
        self.convert_btn.config(state=tk.DISABLED, text="转换中...")
        self.progress_label.config(text="正在转换选中的段落...")
        
        convert_thread = threading.Thread(
            target=self._convert_selected_thread,
            args=(start_segment, end_segment, model, voice, response_format)
        )
        convert_thread.daemon = True
        convert_thread.start()
        
    def _convert_selected_thread(self, start_segment, end_segment, model, voice, response_format):
        try:
            # 转换选中的段落范围
            total_segments = end_segment - start_segment + 1
            converted_count = 0
            
            for i in range(start_segment, end_segment + 1):
                self.root.after(0, lambda s=i+1, t=total_segments, c=i-start_segment+1: 
                               self.progress_label.config(text=f"正在转换第 {s} 段... ({c}/{t})"))
                
                # 转换单个段落
                result = self.tts.convert_and_play_segment(
                    self.segments[i], 
                    i, 
                    model, 
                    voice, 
                    response_format,
                    self.output_dir
                )
                
                # 存储结果
                self.audio_segments.append(result)
                self.segment_paths.append(result[2])  # 文件路径
                
                converted_count += 1
                
            # 更新UI
            self.root.after(0, lambda c=converted_count: self._on_conversion_complete(c))
            
        except Exception as e:
            self.root.after(0, lambda: messagebox.showerror("错误", f"转换过程中出现错误: {str(e)}"))
            self.root.after(0, lambda: self.convert_btn.config(state=tk.NORMAL, text="转换选中段落"))
            
    def _on_conversion_complete(self, converted_count):
        if not self.audio_segments:
            messagebox.showerror("错误", "没有成功转换任何段落")
            self.convert_btn.config(state=tk.NORMAL, text="转换选中段落")
            return
            
        self.convert_btn.config(state=tk.NORMAL, text="转换选中段落")
        self.play_btn.config(state=tk.NORMAL)
        self.progress_label.config(text=f"转换完成，共 {converted_count} 段")
        self.segment_label.config(text=f"段落: 0/{len(self.audio_segments)}")
        
        messagebox.showinfo("完成", f"转换完成，音频文件已保存到 {os.path.basename(self.output_dir)} 目录中")
        
    def toggle_play(self):
        if self.is_playing:
            self.pause_playback()
        else:
            self.start_playback()
            
    def start_playback(self):
        if not self.audio_segments:
            messagebox.showerror("错误", "没有可播放的音频")
            return
            
        self.is_playing = True
        self.play_btn.config(text="暂停")
        self.stop_btn.config(state=tk.NORMAL)
        
        # 在后台线程中播放音频
        play_thread = threading.Thread(target=self._play_audio_thread)
        play_thread.daemon = True
        play_thread.start()
        
    def pause_playback(self):
        self.is_playing = False
        self.play_btn.config(text="播放")
        pygame.mixer.music.pause()
        
    def stop_playback(self):
        self.is_playing = False
        self.play_btn.config(text="播放")
        self.stop_btn.config(state=tk.DISABLED)
        pygame.mixer.music.stop()
        self.progress_var.set(0)
        self.segment_label.config(text=f"段落: 0/{len(self.audio_segments)}")
        
    def _play_audio_thread(self):
        self.current_segment = 0
        
        while self.current_segment < len(self.audio_segments) and self.is_playing:
            # 更新UI
            segment_num = self.current_segment + 1
            self.root.after(0, lambda s=segment_num, t=len(self.audio_segments): 
                           self.segment_label.config(text=f"段落: {s}/{t}"))
            
            # 获取当前段落的音频数据
            _, audio_data, file_path = self.audio_segments[self.current_segment]
            
            try:
                # 加载并播放音频
                if file_path and os.path.exists(file_path):
                    pygame.mixer.music.load(file_path)
                else:
                    pygame.mixer.music.load(io.BytesIO(audio_data))
                    
                pygame.mixer.music.play()
                
                # 等待播放完成
                while pygame.mixer.music.get_busy() and self.is_playing:
                    time.sleep(0.1)
                    
                # 如果播放完成且仍在播放状态，移动到下一段
                if self.is_playing:
                    self.current_segment += 1
                    
            except Exception as e:
                self.root.after(0, lambda: messagebox.showerror("错误", f"播放音频时出现错误: {str(e)}"))
                break
                
        # 播放完成或停止
        self.root.after(0, self._on_playback_complete)
        
    def _on_playback_complete(self):
        self.is_playing = False
        self.play_btn.config(text="播放")
        self.stop_btn.config(state=tk.DISABLED)
        self.progress_var.set(0)
        
        if self.current_segment >= len(self.audio_segments):
            self.segment_label.config(text=f"段落: {len(self.audio_segments)}/{len(self.audio_segments)}")
            messagebox.showinfo("完成", "播放完成")


if __name__ == "__main__":
    root = tk.Tk()
    app = TTSApplication(root)
    root.mainloop()